''' 
    V4.0
'''

from PyQt5.QtWidgets import QWidget,QApplication,QDesktopWidget,QFileDialog
from PyQt5.QtGui import QBitmap,QPainter,QPen,QBrush,QPixmap,QPalette,QDoubleValidator
from PyQt5.QtCore import Qt,QPoint,QRect,QThread,pyqtSignal,QEvent
import time,winsound,os,sys,json,re
from pynput.keyboard import Listener,Key,KeyCode,Controller     # 键盘检测库
from screenShot import Ui_screenShot_window

with open("setting.json","r",encoding="utf-8") as f:
    setting=json.load(f)[0]

# 按键类
class Press(QThread):
    pessed=pyqtSignal(str,bool)
    winOpen=pyqtSignal()
    closeS=pyqtSignal()

    def __init__(self,p):
        super().__init__()
        self.p=p
        self.keyVis=True
        self.pressList=[]   #按键捕捉列表
        self.status=True    #按键开启标志

    def run(self):
        with Listener(on_press = self.press,on_release=self.release) as listener:
            listener.join()
 
    def press(self,key):
        # print(self.pressList)
        # print(key)
        # 将捕捉到的按键保存到列表
        if key in self.pressList:
            self.pressList.remove(key)
        if key not in self.pressList and key!=Key.media_volume_down and key!=Key.media_volume_up:
            self.pressList.append(key)
        if len(self.pressList) > 5:
            self.pressList.remove(self.pressList[0])

        # 截图相关按键
        # N截图
        if KeyCode(char="n")==self.pressList[-1] and Key.alt_r in self.pressList and self.status is True:
            self.pressList.clear()
            winsound.Beep(300,100)
            self.pessed.emit("N",True)
        # C截图
        elif KeyCode(char="c")==self.pressList[-1] and Key.alt_r in self.pressList and self.status is True:
            self.pressList.clear()
            winsound.Beep(300,100)
            self.pessed.emit("C",True)
        # A截图
        elif KeyCode(char="a")==self.pressList[-1] and Key.alt_r in self.pressList and self.status is True:
            self.pressList.clear()
            self.pessed.emit("N",False)
        # 终止截图
        elif Key.backspace==self.pressList[-1] and Key.alt_r in self.pressList and self.status is True:
            self.pressList.clear()
            self.p.programShotPassFlag=True
            winsound.Beep(1000,80)

        # 设置相关按键
        elif KeyCode(char="f")==self.pressList[-1] and Key.alt_r in self.pressList and self.status is True:
            self.pressList.clear()
            os.startfile(setting['install'])
        elif KeyCode(char="p")==self.pressList[-1] and Key.alt_r in self.pressList and self.status is True:
            self.pressList.clear()
            self.winOpen.emit()

        # 程序静默按键
        elif Key.esc==self.pressList[-1] and Key.alt_r in self.pressList:
            if self.status is False:
                self.status=True
            elif self.status is True:
                self.status=False

            self.pressList.clear()
            winsound.Beep(1000,80)
        # 程序退出按键
        elif KeyCode(char="`")==self.pressList[-1] and Key.alt_r in self.pressList:
            self.pressList.clear()
            self.closeS.emit()
            self.p.programShotPassFlag=True

            winsound.Beep(1000,80)
            return False
            
        # 调节音量相关按键
        elif Key.up==self.pressList[-1] and Key.ctrl_r in self.pressList and self.status is True:
            self.pressList.remove(Key.up)
            Controller().press(Key.media_volume_up)
            Controller().release(Key.media_volume_up)
        elif Key.down==self.pressList[-1] and Key.ctrl_r in self.pressList and self.status is True:
            self.pressList.remove(Key.down)
            Controller().press(Key.media_volume_down)
            Controller().release(Key.media_volume_down)

        # 杀进程按键
        elif KeyCode(char="k")==self.pressList[-1] and Key.alt_r in self.pressList and self.status is True:
            self.pressList.clear()

            pid_list=[]
            f=os.popen('tasklist')
            target_tast_list=setting["target_tast_list"]

            # 查找是否有目标程序
            for tasks_massage in f.readlines():
                tasks_name=re.search(r'^(.+?) ',tasks_massage)
                if tasks_name==None:
                    continue
                tasks_name=tasks_name.group(1)
                if tasks_name in target_tast_list:
                    tasks_pid=re.search(r'(\d+) ',tasks_massage)
                    if tasks_pid==None:
                        continue
                    pid_list.append(tasks_pid.group(1))

            # 若找到目标程序就关闭
            if len(pid_list)!=0:
                for pid in pid_list:
                    os.popen('taskkill.exe /f /pid '+(pid))
                winsound.Beep(1000,80)

        # print(key)

    def release(self,key):
        # print(key)
        if not self.keyVis and key in self.pressList:
            self.pressList.remove(key)
        if key == Key.ctrl_r:
            self.pressList.clear()
 
class GetJpg(QWidget):
    """ 
        屏幕定格，方便获取图片
    """
    def __init__(self, parent=None,shotMode="",isProgramShot=False):
        super(GetJpg, self).__init__(parent)
        self.shotMode=shotMode              # 程序截图的模式
        self.isProgramShot=isProgramShot    # 截图是否为程序截图
        self.programShotPassFlag=False      # 程序截图中断标志
        self.inShotEvent=False              # 是否处于截图事件中
        self.m_flag=False
        self.w=setWin()
        self.w.hide()

        # 构造 按键检测 类
        self.p=Press(self)
        self.p.start()
        self.p.pessed.connect(self.open)
        self.p.closeS.connect(self.close)
        self.p.winOpen.connect(self.w.show)

        self.desktopRect = QDesktopWidget().screenGeometry()
        self.setGeometry(self.desktopRect)                       # 改变大小和桌面一样大
        self.blackMask = QBitmap(self.desktopRect.size())        # 截图黑色背景
        self.blackMask.fill(Qt.black)
        self.mask = self.blackMask.copy()                        # 截图遮罩
        self.isDrawing = False

        # 鼠标截图时的初末位置
        self.startPoint = QPoint()
        self.endPoint = QPoint()
        
        # 去边框,透明,置顶
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        
    def open(self,shotMode,isProgramShot):
        """ 
            判断是否为程序截图，以及是否保存。
        """
        self.programShotPassFlag=False
        self.shotMode=shotMode
        self.isProgramShot=isProgramShot

        # 获取当前截图时间，以字符方式保存。
        localT=time.localtime(time.time())
        self.date=(localT[0])*10000+(localT[1])*100+(localT[2])
        self.date=str(self.date)
        time_=localT[3]*100+localT[4]+10000
        time_=str(time_)[1:]
        self.date+=time_

        # 判断是否为程序截图，同时判断是否保存
        if not self.programShotPassFlag and self.isProgramShot:
            time.sleep(setting['pass_time'])
        while not self.programShotPassFlag and self.isProgramShot:
            self.getImage()
            time.sleep(setting['pass_time'])
        if not self.isProgramShot:
            self.setStyleSheet('''background-color:black; ''')
            self.setGeometry(self.desktopRect)
            self.setCursor(Qt.CrossCursor)  # 改变指针样式为十字
            self.setWindowOpacity(0.01) # 改变透明度
            
            self.inShotEvent=True
            
            self.show()

    def getImage(self):
        """ 
            截图，根据鼠标的操作改变截图框。
            根据设置保存图片。
        """
        screenshot = QApplication.primaryScreen().grabWindow(QApplication.desktop().winId())

        if self.isProgramShot:
        # 若是程序截图
            outputRegion = screenshot.copy(700,150, 520,840)    #截图区域

            # 判断截图时刻为第几张图
            list_path=[int(x.split('_')[1].split('.')[0]) for x in os.listdir('.') if self.date in x]
            list_path=sorted(list_path)
            list_path.insert(0,0)   # 如果截图时刻为第一张图，则插入一个0防止出错。
        
            # 发送调试信息，并保存图片
            # print(self.date+'_'+(str)(list_path[-1]+1)+"_"+self.shotMode+".jpg")
            outputRegion.save(self.date+'_'+(str)(list_path[-1]+1)+"_"+self.shotMode+".jpg", format='JPG', quality=100)
            winsound.Beep(300,100)  # 蜂鸣器发声提示
        else:
        # 若不是程序截图，则进入截图界面，定格屏幕。
            # 判断鼠标位置，并发送调试信息，保存图片。
            if self.startPoint.x()<self.endPoint.x():
                x1=self.startPoint.x()
                x2=self.endPoint.x()
            else:
                x1=self.endPoint.x()
                x2=self.startPoint.x()
            if self.startPoint.y()<self.endPoint.y():
                y1=self.startPoint.y()
                y2=self.endPoint.y()
            else:                
                y1=self.endPoint.y()
                y2=self.startPoint.y()
            x2-=(x1-1)
            y2-=(y1-1)
            # print(x1,y1,x2,y2)
            # print(QRect(self.startPoint, self.endPoint))
            outputRegion = screenshot.copy(x1,y1,x2,y2)
            outputRegion.save("test.jpg", format='JPG', quality=100)
    
            self.setCursor(Qt.ArrowCursor)  # 改变指针图片为原本的样式
            self.setGeometry(x1,y1,x2,y2)
            self.setWindowOpacity(1)
            window_pale = QPalette() 
            window_pale.setBrush(self.backgroundRole(), QBrush(QPixmap(".\\test.jpg"))) 
            self.setPalette(window_pale)
            
        clipboard = QApplication.clipboard()
        clipboard.setPixmap(outputRegion)

        self.inShotEvent=False
        # self.hide()
        
        self.startPoint = QPoint()
        self.endPoint = QPoint()
            
    def paintEvent(self, event):
        if self.isDrawing:
            self.mask = self.blackMask.copy()
            pp = QPainter(self.mask)
            pen = QPen()
            pen.setStyle(Qt.NoPen)
            pp.setPen(pen)
            brush = QBrush(Qt.white)
            pp.setBrush(brush)
            pp.drawRect(QRect(self.startPoint, self.endPoint))
            self.setMask(QBitmap(self.mask))
 
    def mousePressEvent(self, event):
        if event.button() == Qt.RightButton:
            self.inShotEvent=False
            self.hide()
        if self.inShotEvent and event.button() == Qt.LeftButton:
        # 如果正在截图事件中，且点击左键触发。
            self.setWindowOpacity(0.6)
            self.startPoint = event.pos()
            self.endPoint = self.startPoint
            self.isDrawing = True
        if not self.inShotEvent and event.button() == Qt.LeftButton:
            self.mousePos=event.pos()
            self.m_flag=True                    # 移动允许
 
    def mouseMoveEvent(self, event):
        if self.inShotEvent and self.isDrawing:
            self.endPoint = event.pos()
            self.update()
        if self.m_flag:
            self.move(self.pos()+event.pos()-self.mousePos)
 
    def mouseReleaseEvent(self, event):
        self.m_flag=False
        if self.inShotEvent and event.button() == Qt.LeftButton:
            self.setWindowOpacity(0)
            self.inShotEvent=False
            self.endPoint = event.pos()
            
            self.getImage()

class setWin(QWidget):
    def __init__(self):
        super().__init__()
        self.w=Ui_screenShot_window()
        self.w.setupUi(self)
        self.file_path=setting["install"]
        self.pass_time=setting["pass_time"]
        self.w.lineEdit_2.setText((str)(setting["pass_time"]))
        self.w.file_line.setText(self.file_path)
        self.m_flag=False

        self.w.lineEdit_2.setValidator(QDoubleValidator())
        self.w.btn_over.clicked.connect(self.over)
        self.w.btn_reload.clicked.connect(self.reload)
        self.w.btn_openPath.clicked.connect(self.openPath)
        self.w.file_btn.clicked.connect(self.chFile)

        # 去边框,透明,置顶
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Tool | Qt.WindowStaysOnTopHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.show()

    def chFile(self):
        file_path= QFileDialog.getExistingDirectory(self).replace("/","\\")
        if file_path:
            self.file_path=file_path
        self.w.file_line.setText(self.file_path)

    def over(self):
        setting["install"]=self.file_path
        setting["pass_time"]=(float)(self.w.lineEdit_2.text())
        os.chdir(setting["install"])
        with open(setting["setting_path"],"w",encoding="utf-8") as f:
            json.dump([setting],f,indent=4,ensure_ascii=False)
        self.hide()

    def reload(self):
        global setting
        with open(setting["setting_path"],"r",encoding="utf-8") as f:
            setting=json.load(f)[0]
        self.hide()

    def openPath(self):
        os.startfile(setting["setting_path"][0:-13])

    def mousePressEvent(self, event):
        if event.button() == Qt.RightButton:
            self.hide()
        if event.button() == Qt.LeftButton:
            self.mousePos=event.pos()
            self.m_flag=True                    # 移动允许
    def mouseMoveEvent(self, event):
        if self.m_flag:
            self.move(self.pos()+event.pos()-self.mousePos)
    def mouseReleaseEvent(self, event):
        self.m_flag=False

if __name__=="__main__":
    os.chdir(setting["install"])
    app=QApplication(sys.argv)
    a=GetJpg()
    a.hide()
    sys.exit(app.exec_())
